<template>
  <div class="article-content-area">
    <!-- AI摘要区域 -->
    <div class="ai-summary-area" v-if="description && description.trim().length">
      <span class="ai-summary-icon">
        <i class="ri-robot-2-line"></i>
      </span>
      <span
        class="ai-summary-text"
        :class="{ collapsed: !expanded, expanded: expanded, 'has-overflow': hasOverflow }"
        ref="summaryTextRef"
      >
        <span ref="typewriterRef"></span>
        <span v-if="!expanded && hasOverflow" class="ai-summary-gradient"></span>
      </span>
      <transition name="fade">
        <button v-if="hasOverflow" class="ai-summary-toggle" @click="toggleExpand">
          {{ expanded ? '收起' : '展开全部' }}
        </button>
      </transition>
      <span class="ai-summary-footer">本摘要由AI智能生成</span>
    </div>
    <!-- 主题切换面板 -->
    <div class="theme-panel" v-if="showThemePanel">
      <div class="theme-panel-title">切换预览主题</div>
      <div class="theme-panel-list">
        <button
          v-for="theme in themes"
          :key="theme.value"
          :class="['theme-btn', { active: previewTheme === theme.value }]"
          @click="setGlobalTheme(theme.value)"
          :title="theme.label"
        >
          <i :class="theme.icon"></i> {{ theme.label }}
        </button>
      </div>
    </div>
    <!-- 目录浮窗 -->
    <div class="toc-float" v-if="showToc && tocItems.length">
      <div class="toc-title">
        <i class="ri-bookmark-3-line"></i> 文章目录
        <button class="close-toc" @click="showToc = false"><i class="ri-close-line"></i></button>
      </div>
      <div class="toc-list">
        <div
          v-for="item in tocItems"
          :key="item.id"
          :class="['toc-item', 'level-' + item.level, { active: activeHeading === item.id }]"
          @click="scrollToHeading(item.id)"
        >
          {{ item.text }}
        </div>
      </div>
    </div>
    <!-- 文章内容 -->
    <div class="article-content markdown-body" ref="contentRef">
      <MdPreview
        :model-value="content"
        :preview-theme="previewTheme"
        @on-html-changed="extractToc"
      />
      <div class="article-end-divider">
        <span>END</span>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, nextTick, onMounted, onBeforeUnmount, watch, defineExpose } from 'vue'
import { MdPreview } from 'md-editor-v3'
import 'md-editor-v3/lib/style.css'
import bus from '@/utils/eventBus'

const props = defineProps({
  content: String,
  tocItems: Array,
  previewTheme: String,
  description: { type: String, default: '' },
})
const emit = defineEmits(['theme-change', 'toc-update'])

const themes = [
  { value: 'github', label: 'GitHub', icon: 'ri-github-fill' },
  { value: 'vuepress', label: 'VuePress', icon: 'ri-book-3-line' },
  { value: 'smart-blue', label: '深蓝', icon: 'ri-drop-fill' },
  { value: 'cyanosis', label: '水蓝', icon: 'ri-water-flash-line' },
]

const showToc = ref(false)
const showThemePanel = ref(false)
const contentRef = ref(null)
const activeHeading = ref('')
const typewriterRef = ref(null)
const summaryTextRef = ref(null)
const expanded = ref(false)
const hasOverflow = ref(false)
const summaryText = ref('')

function toggleExpand() {
  expanded.value = !expanded.value
}

function checkOverflow() {
  nextTick(() => {
    const el = summaryTextRef.value
    if (el) {
      // 4行高度
      const lineHeight = parseFloat(getComputedStyle(el).lineHeight) || 24
      const maxHeight = lineHeight * 4
      hasOverflow.value = el.scrollHeight - 2 > maxHeight
    }
  })
}

// 提取目录
function extractToc() {
  nextTick(() => {
    if (!contentRef.value) return
    const headings = contentRef.value.querySelectorAll('h1, h2, h3, h4')
    const items = []
    headings.forEach((heading, idx) => {
      if (!heading.id) heading.id = `heading-${idx}`
      items.push({ id: heading.id, text: heading.textContent, level: parseInt(heading.tagName[1]) })
    })
    emit('toc-update', items)
  })
}

// 滚动到指定标题
function scrollToHeading(id) {
  const el = document.getElementById(id)
  if (el) {
    // 假设顶部菜单栏高度为 64px，可根据实际调整
    const menuHeight = 64 + 8 // 8px 额外间距
    const rect = el.getBoundingClientRect()
    const scrollTop = window.scrollY || window.pageYOffset
    const targetY = rect.top + scrollTop - menuHeight
    window.scrollTo({ top: targetY, behavior: 'smooth' })
    activeHeading.value = id
    showToc.value = false
  }
}

// 目录高亮
function updateActiveHeading() {
  if (!contentRef.value) return
  const headings = contentRef.value.querySelectorAll('h1, h2, h3, h4')
  const scrollY = window.scrollY
  let current = ''
  for (const heading of headings) {
    const top = heading.getBoundingClientRect().top + scrollY
    if (top - 100 <= scrollY) current = heading.id
    else break
  }
  activeHeading.value = current
}

function setGlobalTheme(theme) {
  emit('theme-change', theme)
  localStorage.setItem('global-article-preview-theme', theme)
  showThemePanel.value = false
}

function handleGlobalClick(e) {
  // 目录弹窗
  const tocFloat = document.querySelector('.toc-float')
  const tocBtn = document.querySelector('.toc-btn')
  if (
    showToc.value &&
    tocFloat &&
    !tocFloat.contains(e.target) &&
    !(tocBtn && tocBtn.contains(e.target))
  ) {
    showToc.value = false
  }
  // 主题弹窗
  const themePanel = document.querySelector('.theme-panel')
  const settingBtn = document.querySelector('.setting-btn')
  if (
    showThemePanel.value &&
    themePanel &&
    !themePanel.contains(e.target) &&
    !(settingBtn && settingBtn.contains(e.target))
  ) {
    showThemePanel.value = false
  }
}

watch([showToc, showThemePanel], ([toc, theme]) => {
  // 保证同一时刻只显示一个弹窗
  if (toc && theme) {
    showThemePanel.value = false
  }
  if (toc || theme) {
    document.addEventListener('mousedown', handleGlobalClick)
  } else {
    document.removeEventListener('mousedown', handleGlobalClick)
  }
})

onMounted(() => {
  const saved = localStorage.getItem('global-article-preview-theme')
  if (saved && themes.some((t) => t.value === saved)) {
    emit('theme-change', saved)
  }
  window.addEventListener('scroll', updateActiveHeading)
  bus.on('open-article-toc', openToc)
  bus.on('open-article-theme', openThemePanel)
  // 初次渲染摘要
  nextTick(() => startTyping(props.description))
})

onBeforeUnmount(() => {
  document.removeEventListener('mousedown', handleGlobalClick)
  bus.off('open-article-toc', openToc)
  bus.off('open-article-theme', openThemePanel)
})

// 暴露方法供父组件调用
function openToc() {
  showToc.value = true
  showThemePanel.value = false
}
function openThemePanel() {
  showThemePanel.value = true
  showToc.value = false
}
defineExpose({ openToc, openThemePanel })

// 监听摘要变更，重新触发打字效果
watch(
  () => props.description,
  (val) => {
    nextTick(() => startTyping(val))
  },
)

// 启动打字机效果
function startTyping(text) {
  const content = typeof text === 'string' ? text : ''
  summaryText.value = content
  expanded.value = false
  if (!content) {
    if (typewriterRef.value) typewriterRef.value.textContent = ''
    hasOverflow.value = false
    return
  }
  if (!typewriterRef.value) return
  typewriterRef.value.textContent = ''
  let i = 0
  function type() {
    if (!typewriterRef.value) return
    if (i <= summaryText.value.length) {
      typewriterRef.value.textContent = summaryText.value.slice(0, i)
      i++
      setTimeout(type, 18)
      checkOverflow()
    }
  }
  type()
}
</script>

<style lang="scss" scoped>
.article-content-area {
  position: relative;
  margin-bottom: 40px;
  .ai-summary-area {
    position: relative;
    display: flex;
    flex-direction: column;
    background: #f6f8fa;
    border-radius: 16px;
    padding: 28px 28px 32px 28px;
    margin: 32px 0 22px 0;
    box-shadow: 0 4px 24px 0 rgba(0, 0, 0, 0.06);
    border: 1px solid #e3e8ee;
    min-height: 56px;
    .ai-summary-icon {
      position: absolute;
      left: 18px;
      top: -18px;
      width: 38px;
      height: 38px;
      background: #eaf3ff;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 22px;
      color: var(--primary-color);
      box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.04);
      border: 1.5px solid #d0e2ff;
      z-index: 2;
    }
    .ai-summary-text {
      flex: 1;
      min-height: 22px;
      letter-spacing: 0.01em;
      font-family: inherit;
      word-break: break-all;
      margin-left: 0;
      margin-top: 0;
      font-size: 16px;
      color: var(--text-color-secondary);
      line-height: 1.8;
      max-height: none;
      overflow: visible;
      position: relative;
      transition: max-height 0.36s cubic-bezier(0.4, 0, 0.2, 1);
      &.collapsed {
        max-height: calc(1.8em * 4);
        overflow: hidden;
      }
      &.expanded {
        max-height: 1200px;
        overflow: visible;
      }
      &.has-overflow {
        padding-bottom: 18px;
      }
      .ai-summary-gradient {
        content: '';
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
        height: 2.8em;
        background: linear-gradient(180deg, rgba(246, 248, 250, 0) 0%, #f6f8fa 90%);
        pointer-events: none;
        border-radius: 0 0 16px 16px;
      }
    }
    .ai-summary-toggle {
      position: absolute;
      left: 50%;
      bottom: 8px;
      transform: translateX(-50%);
      background: rgba(255, 255, 255, 0.85);
      color: var(--primary-color);
      border: none;
      border-radius: 16px;
      padding: 3px 18px 4px 18px;
      font-size: 14px;
      font-weight: 500;
      box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.06);
      cursor: pointer;
      transition:
        background 0.18s,
        color 0.18s,
        box-shadow 0.18s;
      z-index: 3;
      &:hover {
        background: var(--primary-color-light-10);
        color: var(--primary-color-dark);
        box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.1);
      }
    }
    .ai-summary-footer {
      position: absolute;
      right: 18px;
      bottom: 10px;
      font-size: 12px;
      color: #b0b4ba;
      user-select: none;
      z-index: 2;
    }
  }
  .fade-enter-active,
  .fade-leave-active {
    transition: opacity 0.25s;
  }
  .fade-enter-from,
  .fade-leave-to {
    opacity: 0;
  }
  .theme-panel {
    position: fixed;
    right: 80px;
    top: 50%;
    transform: translateY(-50%);
    background: #fff !important;
    border-radius: 14px;
    box-shadow: 0 12px 40px 0 rgba(0, 0, 0, 0.22);
    z-index: 1002;
    border: 1px solid var(--border-color-light);
    padding: 18px 24px;
    min-width: 180px;
    backdrop-filter: blur(0);
    .theme-panel-title {
      font-size: 15px;
      font-weight: 600;
      margin-bottom: 12px;
      color: var(--primary-color);
    }
    .theme-panel-list {
      display: flex;
      flex-direction: column;
      gap: 10px;
      .theme-btn {
        width: 100%;
        border-radius: 8px;
        border: none;
        background: var(--bg-color-light);
        color: var(--text-color-secondary);
        display: flex;
        align-items: center;
        gap: 8px;
        font-size: 15px;
        padding: 8px 12px;
        cursor: pointer;
        transition:
          background 0.18s,
          color 0.18s;
        &:hover {
          background: var(--primary-color-light-10);
          color: var(--primary-color);
        }
        &.active {
          background: var(--primary-color);
          color: #fff;
        }
        i {
          font-size: 16px;
        }
      }
    }
    @media (max-width: 600px) {
      right: 8px;
      top: auto;
      bottom: 120px;
      transform: none;
      min-width: 120px;
      padding: 10px 6px;
      background: #fff;
      :root.dark & {
        background: #18181c;
      }
    }
    @media (min-width: 601px) {
      right: 24px;
      bottom: 110px;
      top: auto;
      transform: none;
    }
  }
  .toc-float {
    position: fixed;
    right: 80px;
    top: 50%;
    transform: translateY(-50%);
    width: 280px;
    background: #fff !important;
    border-radius: 14px;
    box-shadow: 0 12px 40px 0 rgba(0, 0, 0, 0.22);
    z-index: 1002;
    border: 1px solid var(--border-color-light);
    backdrop-filter: blur(0);
    @media (max-width: 600px) {
      right: 8px;
      top: auto;
      bottom: 60px;
      width: 90vw;
      max-width: 350px;
      transform: none;
      background: #fff;
      :root.dark & {
        background: #18181c;
      }
    }
    @media (min-width: 601px) {
      right: 24px;
      bottom: 110px;
      top: auto;
      transform: none;
    }
    .toc-title {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 14px 18px;
      font-weight: 600;
      font-size: 16px;
      border-bottom: 1px solid var(--border-color-light);
      .close-toc {
        background: none;
        border: none;
        color: var(--text-color-secondary);
        font-size: 18px;
        cursor: pointer;
      }
    }
    .toc-list {
      max-height: 60vh;
      overflow-y: auto;
      padding: 10px 0;
      .toc-item {
        padding: 8px 24px;
        font-size: 14px;
        color: var(--text-color-secondary);
        cursor: pointer;
        border-left: 3px solid transparent;
        transition: all 0.2s;
        &.active {
          color: var(--primary-color);
          background: var(--primary-color-light-10);
          border-left-color: var(--primary-color);
          font-weight: 600;
        }
        &.level-1 {
          font-size: 15px;
          font-weight: 600;
        }
        &.level-2 {
          padding-left: 36px;
        }
        &.level-3 {
          padding-left: 48px;
          font-size: 13px;
        }
        &.level-4 {
          padding-left: 60px;
          font-size: 12px;
          color: var(--text-color-light);
        }
      }
    }
  }
  .article-content,
  .markdown-body,
  .md-editor-preview,
  .md-editor-preview-wrapper,
  .md-editor-previewOnly {
    font-family: 'Source Han Sans SC', '思源黑体', 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei',
      sans-serif !important;
  }
  .article-end-divider {
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 32px 0 0 0;
    position: relative;
    user-select: none;
    &::before,
    &::after {
      content: '';
      flex: 1;
      border-top: 1.5px dashed #d3d6db;
      margin: 0 18px;
      height: 0;
      transition: border-color 0.3s;
    }
    span {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 44px;
      height: 44px;
      border-radius: 50%;
      background: #f7f8fa;
      border: 1.5px solid #e3e8ee;
      color: #b0b4ba;
      font-size: 15px;
      font-weight: 600;
      letter-spacing: 0.18em;
      box-shadow: none;
      z-index: 1;
      transition:
        background 0.3s,
        border-color 0.3s,
        color 0.3s;
    }
    &:hover span {
      color: var(--primary-color);
      border-color: var(--primary-color);
    }
  }
  :root.dark .article-end-divider {
    &::before,
    &::after {
      border-top: 1.5px dashed #393a3f;
    }
    span {
      background: #232329;
      border-color: #393a3f;
      color: #888b97;
    }
  }
}
:root.dark .article-content-area .theme-panel,
:root.dark .article-content-area .toc-float {
  background: #18181c !important;
}
.toc-float,
.theme-panel {
  @media (min-width: 601px) {
    bottom: 110px;
    top: auto;
    transform: none;
    right: 24px;
  }
}
@media (max-width: 600px) {
  .toc-float {
    width: 95vw;
    max-width: 350px;
    right: 8px;
    top: auto;
    bottom: 80px;
    transform: none;
    background: #fff;
    .toc-list {
      max-height: 60vh;
      overflow-y: auto;
      /* 滚动条美化 */
      scrollbar-width: thin;
      scrollbar-color: var(--primary-color) #f0f0f0;
    }
    .toc-list::-webkit-scrollbar {
      width: 6px;
      background: #f0f0f0;
    }
    .toc-list::-webkit-scrollbar-thumb {
      background: var(--primary-color);
      border-radius: 4px;
    }
  }
}
</style>
